home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
choices
/
chcssml1.lha
/
Process.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-02-06
|
7KB
|
293 lines
/*
* This file is part of the Choices Operating System Simulator
* Developed by: The TAPESTRY Parallel Computing Laboratory
* University of Illinois at Urbana-Champaign
* Department of Computer Science
* 1304 W. Springfield Ave.
* Urbana, IL 61801
*
* Copyright (c) 1987, 1988, 1989 The University of Illinois Board of Trustees.
* All Rights Reserved.
* CONFIDENTIAL INFORMATION. Distribution restricted under license agreement.
*
* Author: Gary M. Johnston (johnston@cs.uiuc.edu)
* Project Manager and Principal Investigator: Roy Campbell (roy@cs.uiuc.edu)
*
* Funded by: NSF TAPESTRY Grant No. 1-5-30035, NASA ICLASS Grant
* No. 1-5-25469 and No. NSG1471 and AT&T Metronet Grant No. 1-5-37411.
*/
/*
* Process.c - Implementations of classes ProcessTask,
* ProcessStatistics, Process, and IdleProcess.
*
* $Header: Process.c,v 1.8 88/02/16 08:45:00 johnston Exp $
* $Locker: johnston $
*/
#include <task.h>
#include "Assert.h"
#include "Debug.h"
#include "Name.h"
#include "CPU.h"
#include "Exception.h"
#include "Process.h"
#include "Clock.h"
#include "Print.h"
ProcessTask::ProcessTask( Process * process, ProcessEntry entry, void * argp,
int preemptable, char * procName )
: ( CatName( MakeName( "ProcessTask", this ),
CatName( " for ", procName ) ) )
{
Debug("%s::ctor: entry (*0x%08x)(0x%08x).\n", getName(), entry, argp);
Assert(entry != 0);
/*
* Initialize.
*/
ProcessTask::process = process;
Assert(preemptable == 0);
ProcessTask::preemptable = preemptable;
/*
* Initially we're stopped.
* Eventually we'll be put on a CPU and started.
* When that happens, we call the specified procedure (with argument).
*/
Debug("%s::ctor: sleeping.\n", getName());
sleep();
Debug("%s::ctor: calling (*0x%08x)(0x%08x).\n", getName(), entry, argp);
int result = (*entry)(argp);
Debug("%s::ctor: (*0x%08x)(0x%08x) returned %d.\n",
getName(), entry, argp, result);
/*
* Terminate ourself:
* Disallow preemption.
* Send the TerminateVector to the CPU we're running on.
* Delay, waiting for the Exception handler to delete us.
*/
(void) setPreemptable( 0 );
Assert(process != 0);
Assert(process->cpu != 0);
process->cpu->interrupt( TerminateVector );
Debug("%s::ctor: waiting.\n", getName());
for (;;)
delay(1);
NotReached();
}
char *
ProcessTask::getName()
{
return (t_name);
}
int
ProcessTask::isPreemptable()
{
return (preemptable);
}
int
ProcessTask::setPreemptable( int flag )
{
int mask = BlockClock();
int oldFlag = preemptable;
preemptable = flag;
UnblockClock( mask );
return ( oldFlag );
}
ProcessStatistics::ProcessStatistics( Process * p )
{
process = p;
runCount = 0;
runTime = 0;
lastRun = 0;
}
void
ProcessStatistics::print()
{
Print( "%s ends %d ticks, dispatched %d times, total run time %d ticks.\n",
process->getName(), clock, runCount, runTime );
}
Process::Process(ProcessEntry entry, void * argp, int preemptable, char * name)
: ( name ? name : MakeName( "Process", this ) )
{
/*
* Enter critical section.
*/
int mask = 0;
int flag = IsAProcessTask(thistask);
if ( flag )
mask = ((ProcessTask *) thistask)->setPreemptable(0);
Debug("%s::ctor: entry (*0x%08x)(0x%08x) (%spreemptable).\n",
getName(), entry, argp, (preemptable ? "" : "not "));
Assert(entry != 0);
/*
* Initialize and create ProcessTask (last to avoid a race with it).
* Initially the ProcessTask is not preemptable.
*/
statistics = new ProcessStatistics( this );
cpu = 0;
schedulerInfo = 0;
quantum = RunToCompletion;
processTask = new ProcessTask( this, entry, argp, 0, getName() );
Assert(processTask != 0);
/*
* Wait for the ProcessTask to go to sleep before returning.
* This avoids a race condition in which the Process might
* be woken up before it was asleep.
*/
while ( processTask->rdstate() == RUNNING )
thistask->delay( 0 );
Debug("%s::ctor: process task %s.\n",
getName(), processTask->getName());
processTask->setPreemptable(preemptable);
/*
* Leave critical section.
*/
if (flag)
(void) ((ProcessTask *) thistask)->setPreemptable(mask);
}
void
Process::setQuantum( int q )
{
Assert((q == RunToCompletion) || (q > 0));
quantum = q;
}
int
Process::getQuantum()
{
return (quantum);
}
int
Process::getState()
{
Assert(processTask != 0);
return (processTask->rdstate());
}
Process::~Process()
{
/*
* Get rid of the ProcessTask and the scheduler info.
*/
Debug("%s::dtor: state %d.\n", getName(), getState());
Assert(getState() == IDLE);
processTask->cancel(0);
Assert(getState() == TERMINATED);
delete processTask;
if (schedulerInfo != 0)
delete schedulerInfo;
/*
* Print and delete statistics.
* We don't update here because we must have been previously
* stopped, at which time the statistics were updated.
*/
Assert(statistics != 0);
statistics->print();
delete statistics;
}
void
Process::stop()
{
/*
* Stop the ProcessTask.
* Clear the CPU (because we're not running anymore).
*/
Assert(cpu != 0);
Assert(processTask != 0);
Debug("%s::stop %s on %s.\n",
getName(), processTask->getName(), cpu->getName());
Assert(getState() == RUNNING);
cpu = 0;
/*
* Update statistics.
*/
Assert(statistics != 0);
Assert(clock >= statistics->lastRun);
statistics->runTime += (clock - statistics->lastRun);
processTask->sleep();
}
void
Process::start(CPU * cpu)
{
/*
* Update statistics.
*/
Assert(statistics != 0);
statistics->runCount++;
statistics->lastRun = clock;
/*
* Set the CPU we're running on.
* Start the ProcessTask.
*/
Assert(cpu != 0);
Debug("%s::start %s on %s.\n",
getName(), processTask->getName(), cpu->getName());
Assert(getState() == IDLE);
Assert(cpu->managerRunning());
Process::cpu = cpu;
processTask->delay(0);
Assert(getState() == RUNNING);
}
int
IdleProcessEntry(void * vcpu)
{
CPU * cpu = (CPU *) vcpu;
Assert(cpu != 0);
Debug("IdleProcessEntry(%s).\n", cpu->getName());
// Set CPU IdleException.
IdleException * idleException = new IdleException();
Assert(idleException != 0);
Debug("IdleProcessEntry: set vector %d to %s on %s.\n",
IdleVector, idleException->getName(), cpu->getName());
cpu->setException(IdleVector,idleException);
/*
* Continually check the scheduler to see if there is a "real" Process
* which could be run. If there is one, send the IdleVector.
* Relinquish each time around the loop to avoid starving other tasks.
*/
for (;;) {
if (!cpu->getScheduler()->isEmpty()) {
Debug("IdleProcessEntry: send %d to %s.\n",
IdleVector, cpu->getName());
cpu->interrupt(IdleVector);
}
thistask->delay(1);
}
NotReached();
return (0);
}
IdleProcess::IdleProcess(CPU * cpu, char * name)
: ( (ProcessEntry) IdleProcessEntry,
(void *) cpu, 0,
( name ? name : MakeName( "IdleProcess", this ) ) )
{
/*
* We have nothing further to do.
*/
Debug("%s::ctor for %s (%s).\n",
getName(), cpu->getName(), processTask->getName());
}